package com.bourse.dbfeeder.services.feeder;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.log4j.Logger;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;

import com.bourse.core.services.utils.IsinCodeFactory;
import com.bourse.core.utils.Cotation;
import com.bourse.core.utils.IndiceComposition;
import com.bourse.core.utils.IsinCode;
import com.bourse.dbfeeder.constants.EuronextConstants;

public class EuronextDataDownloadServiceImpl implements DataLoaderService {

	private static final Logger LOGGER = Logger
			.getLogger(EuronextDataDownloadServiceImpl.class);

	private static final int ISIN = 1;
	private static final int COURS = 7;
	private static final int VOLUME = 8;
	private static final int DATETIME = 10;
	private static final int JOUR_PREMIER = 18;
	private static final int PLUS_HAUT = 19;
	private static final int PLUS_BAS = 21;

	private static final DateTimeFormatter inputFormatter = new DateTimeFormatterBuilder()
		.appendMonthOfYear(2).appendLiteral("/").appendDayOfMonth(2).appendLiteral("/")
		.appendYear(2, 2).appendLiteral(" ").appendHourOfDay(2).appendLiteral(":")
		.appendMinuteOfHour(2).toFormatter();
		
	/**
	 * Get the cotation from Euronext
	 * 
	 * La date de la cotation est enregistr�es dans les donn�es statiques en "LastCotation"
	 * Dans la table des cotations la date sera celle le LastCotation.
	 * 
	 */
	public Map<IsinCode, List<Cotation>> getCotations() {
	
		LOGGER.info("[EURONEXT COTATION DATA DL] - Starting data downlaod");
		Map<IsinCode, List<Cotation>> cotationsMap = new HashMap<IsinCode, List<Cotation>>();

		/** First download cotations */
		String cotationDatas = downloadFile(EuronextConstants.COTATIONS_DATAS);
		LOGGER.info("[EURONEXT COTATION DATA DL] - Datas downloaded");

		/** Parse received file */
		String[] lines = cotationDatas.split("\n");
		for (int i = 0; i < lines.length; i++) {

			String line = lines[i];
			try {
				String[] champs = null;
				line = line.replace(",", " ");
				champs = line.split(";");

				if (i > 3) {
					String theDate = champs[DATETIME];
					String isinCode = champs[ISIN];
					IsinCode isin = IsinCodeFactory.getInstance().getIsinCode(isinCode);
					
					try{
						DateTime dateTime = inputFormatter.parseDateTime(theDate);			
						dateTime= dateTime.plusYears(2000);
						DateMidnight currentDate = dateTime.toDateMidnight();

						/** Handle cotation datas */
						List<Cotation> cotations = cotationsMap.get(isin);
						if (cotations == null) {
							cotations= new ArrayList<Cotation>();
							cotationsMap.put(isin, cotations);
						}
						Cotation cotation = new Cotation();
						cotation.setIsin(isin);
						cotation.setCours(Double.valueOf(champs[COURS]));
						cotation.setOuverture(Double.valueOf(champs[JOUR_PREMIER]));
						cotation.setPlusBas(Double.valueOf(champs[PLUS_BAS]));
						cotation.setPlusHaut(Double.valueOf(champs[PLUS_HAUT]));
						cotation.setVolume(champs[VOLUME]);
						cotation.setDate(currentDate);
						cotations.add(cotation);
												
					}catch(Exception e){
						LOGGER.warn("[EURONEXT COTATION DATA DL] "+e.getMessage()+" for isin: "+isin);				
					}
				}
			} catch (Exception e) {
				LOGGER.error("[EURONEXT COTATION DATA DL] - Probleme with line: \n"
						+ line + "\n " + e.getMessage());
			}
		}
		LOGGER.info("[EURONEXT COTATION DATA DL] - Datas formatted");
		return cotationsMap;

	}

	/**
	 * Get the index composition stock from euronext
	 * 
	 * La date du jour est utilis�e pour la composition
	 */
	public Map<IsinCode,List<IndiceComposition>> getIndexComposition() {

		Map<IsinCode, List<IndiceComposition>> indiceComposition = new HashMap<IsinCode, List<IndiceComposition>>();

		for (String url : EuronextConstants.INDEX_COMPO_TAB) {

			LOGGER.info("[EURONEXT INDICE COMPOSITION DL] - Downloading data for "+url.substring(73,85));
			String datas = downloadFile(url);
			String[] lines = datas.split("\n");
			IsinCode isin = null;
			List<IndiceComposition> list = null;
						
			for (int i = 0; i < lines.length; i++) {
				String currentLine = lines[i];
				try{
					String[] line = currentLine.split(";");
					if (i == 0) {
						String isinCode = line[1];
						isin = IsinCodeFactory.getInstance().getIsinCode(isinCode);
						list = indiceComposition.get(isin);
						if (list == null) {
							list = new ArrayList<IndiceComposition>();
						}
						indiceComposition.put(isin, list);
					}
					if (i > 2) {
						String theDate = line[DATETIME]; 
						try{
							inputFormatter.parseDateTime(theDate);
							DateMidnight today = new DateMidnight();
							String isinCodeUnder = line[1];
							IsinCode isinUnder = IsinCodeFactory.getInstance().getIsinCode(isinCodeUnder);
							list.add(new IndiceComposition(isin, isinUnder, today));
						}catch(Exception e){
							LOGGER.warn("[EURONEXT INDICE COMPOSITION DL] - "+e.getMessage()+" for isin: "+isin+" date: "+theDate);
						}
					}
				}catch(Exception e){
					LOGGER.error("[EURONEXT INDICE COMPOSITION DL] - Problem with line: \n"+currentLine+"\n"+ e.getMessage());					
				}
			}

		}
		return indiceComposition;

	}

	/**
	 * Return datas from an url
	 * 
	 * @param url
	 * @return
	 */
	private String downloadFile(String url) {

		HttpClient client = new HttpClient();
		GetMethod method = new GetMethod(url);
		method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
				new DefaultHttpMethodRetryHandler(3, false));

		try {
			int statusCode = client.executeMethod(method);
			if (statusCode != HttpStatus.SC_OK) {
				System.err.println("Method failed: " + method.getStatusLine());
			}
			InputStream responseBody = method.getResponseBodyAsStream();
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					responseBody));
			StringBuilder sb = new StringBuilder();
			String line = null;

			while ((line = reader.readLine()) != null) {
				sb.append(line + "\n");
			}
			return sb.toString();

		} catch (HttpException e) {
			e.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		} finally {
			method.releaseConnection();
		}
		return null;
	}

}
